#include <rtthread.h>
#include <rtdevice.h>
#include <string.h>
#include <rtconfig.h>
#include "board.h"
#include "at32f435_437.h"
#include "manager_queue.h"
#include "wiota_app.h"
#include "module_queue_struct.h"
#include "led_manager.h"
#include "manager_queue_comm.h"
#include "uc_log.h"

////////////////////////////////////////////////////////////////////////////////

typedef struct _led_resource
{
    led_id_e id;                   // work/blue/cat1...
    unsigned int pin;              // GPIO口
    led_event_e recover;           // 闪烁完成后需要恢复的状态，LED_ON或者LED_OFF或者LED_BLINK_KEEP
    led_event_e current;           // 当前运行状态，LED_ON或者LED_OFF或者LED_BLINK_KEEP
    int current_state;             // 当前状态，LED_ON或者LED_OFF
    unsigned int event_start_time; // 事件开始时间
    unsigned int change_time;      // 状态切换时间, LED_ON <-> LED_OFF 状态切换时间
} led_res_t;

typedef struct _led_msg_data
{
    led_id_e id;
    led_event_e e;
} led_msg_data_t;

////////////////////////////////////////////////////////////////////////////////

#ifdef UC_GATEWAY_HARDWARE

#define PIN_RUN GET_PIN(D, 13)  // LED 15/CN10
#define PIN_BLUE GET_PIN(D, 14) // LED 14
#define PIN_CAT1 GET_PIN(G, 2)  // LED 10
#define PIN_WIFI GET_PIN(G, 3)  // LED 11
#define PIN_ETH GET_PIN(G, 4)   // LED 12
#define PIN_WIOTA GET_PIN(G, 5) // LED 13
#define PIN_MQTT GET_PIN(A, 0)  // CN5

static led_res_t s_led_resource[] = {
    // seq num  pin num    recover           current   current_state event_start_time change_time
    {LED_RUN, PIN_RUN, LED_E_BLINK_KEEP, LED_E_DEF, 0, 0, 0},
    {LED_BLUE, PIN_BLUE, LED_E_NORMAL, LED_E_DEF, 0, 0, 0},
    {LED_CAT1, PIN_CAT1, LED_E_EXCEPTION, LED_E_DEF, 0, 0, 0},
    {LED_WIFI, PIN_WIFI, LED_E_EXCEPTION, LED_E_DEF, 0, 0, 0},
    {LED_ETH, PIN_ETH, LED_E_EXCEPTION, LED_E_DEF, 0, 0, 0},
    {LED_WIOTA, PIN_WIOTA, LED_E_EXCEPTION, LED_E_DEF, 0, 0, 0},
    {LED_MQTT, PIN_MQTT, LED_E_EXCEPTION, LED_E_DEF, 0, 0, 0}};

#else

// 低电平点亮
#define PIN_WORK GET_PIN(D, 15)        // D7
#define PIN_BLUE GET_PIN(C, 7)         // D8
#define PIN_STATE GET_PIN(C, 6)        // D9
// 高电平点亮
#define PIN_MQTT_ERR GET_PIN(D, 9)     // D21 down
#define PIN_MQTT_STATE GET_PIN(D, 8)   // D21 up
#define PIN_WIOTA_STATE GET_PIN(D, 10) // D22 up

static led_res_t s_led_resource[] = {
    // seq num        pin num          recover           current   current_state event_start_time change_time
    {LED_RUN, PIN_RUN, LED_E_BLINK_KEEP, LED_E_DEF, 0, 0, 0},
    {LED_BLUE, PIN_BLUE, LED_E_NORMAL, LED_E_DEF, 0, 0, 0},
    {LED_STATE, PIN_STATE, LED_E_NORMAL, LED_E_DEF, 0, 0, 0},
    {LED_MQTT_ERR, PIN_MQTT_ERR, LED_E_NORMAL, LED_E_DEF, 0, 0, 0},
    {LED_MQTT_STATE, PIN_MQTT_STATE, LED_E_NORMAL, LED_E_DEF, 0, 0, 0},
    {LED_WIOTA_STATE, PIN_WIOTA_STATE, LED_E_NORMAL, LED_E_DEF, 0, 0, 0},
};
#endif

#define LED_RESOURCE_SIZE (sizeof(s_led_resource) / sizeof(s_led_resource[0]))

// static void *led_queue_handle = NULL;

////////////////////////////////////////////////////////////////////////////////
/**
 * @brief    LED 点亮
 * @param[IN]    pin 要控制的PIN脚
 * @param[IN]    on  0灭, 1亮
 *
 */
static void led_on(unsigned int pin, char on)
{
#ifndef UC_GATEWAY_HARDWARE
    switch (pin)
    {
    case PIN_RUN:
    case PIN_BLUE:
    case PIN_CAT1:
        // 低电平点亮
        on = on ? PIN_LOW : PIN_HIGH;
        break;
    case PIN_MQTT_ERR:
    case PIN_MQTT:
    case PIN_WIOTA:
        // 高电平点亮
        on = on ? PIN_HIGH : PIN_LOW;
        break;
    default:
        break;
    }
#endif
    rt_pin_write(pin, on);
}

// led引脚初始化
static void led_pin_init(void)
{
    for (int i = 0; i < LED_RESOURCE_SIZE; i++)
    {
        rt_pin_mode(s_led_resource[i].pin, PIN_MODE_OUTPUT);
        led_on(s_led_resource[i].pin, 1);
    }
    led_on(s_led_resource[LED_BLUE].pin, 0);
    s_led_resource[LED_RUN].event_start_time = rt_tick_get();
    s_led_resource[LED_RUN].change_time = s_led_resource[LED_RUN].event_start_time;
    led_on(s_led_resource[LED_RUN].pin, 1);
    s_led_resource[LED_RUN].current_state = LED_E_EXCEPTION;
}

/**
 * @brief    LED 保持闪烁
 * @param[IN/OUT]    led_res_p 对应一个led_res_t资源
 *
 */
static void led_blink_keep(led_res_t *led_res_p)
{
    unsigned int current_tick = rt_tick_get();
    unsigned int change_interval_time = 0;
    if (RT_NULL == led_res_p)
        return;
    // 如果当前时间大于等于改变时间，则计算改变间隔时间
    if (led_res_p->change_time)
    {
        if (current_tick > led_res_p->change_time)
        {
            change_interval_time = current_tick - led_res_p->change_time;
        }
        else
        {
            change_interval_time = led_res_p->change_time - current_tick;
        }
    }
    if (change_interval_time > LED_BLINK_TIME - 10)
    {
        led_on(led_res_p->pin, (LED_E_EXCEPTION == led_res_p->current_state) ? 0 : 1);
        led_res_p->current_state = (LED_E_EXCEPTION == led_res_p->current_state) ? LED_E_NORMAL : LED_E_EXCEPTION;
        led_res_p->change_time = current_tick;
    }
}

/**
 * @brief    LED 亮灭各一次，完成后回到recover状态
 * @param[IN/OUT]    led_res_p 对应一个led_res_t资源
 *
 */
static void led_blink_once(led_res_t *led_res_p)
{
    unsigned int current_tick = rt_tick_get();
    unsigned int start_interval_time = 0;
    unsigned int change_interval_time = 0;
    if (RT_NULL == led_res_p)
        return;
    // 如果当前时间大于等于改变时间，则计算改变间隔时间
    if (led_res_p->change_time)
    {
        if (current_tick > led_res_p->change_time)
        {
            change_interval_time = current_tick - led_res_p->change_time;
        }
        else
        {
            change_interval_time = led_res_p->change_time - current_tick;
        }
    }
    // TRACE_D("change_interval_time %d", change_interval_time);

    // 如果当前时间大于事件开始时间，则计算当前时间与事件开始时间的差值
    if (led_res_p->event_start_time)
    {
        if (current_tick > led_res_p->event_start_time)
        {
            start_interval_time = current_tick - led_res_p->event_start_time;
        }
        else
        {
            start_interval_time = led_res_p->event_start_time - current_tick;
        }
    }
    // TRACE_D("start_interval_time %d", start_interval_time);

    // 判断当前时间是否在闪烁时间范围内，如果是，则根据当前状态改变引脚电平，并记录当前时间
    if ((start_interval_time >= LED_BLINK_TIME) &&
        (start_interval_time < LED_BLINK_TIME * 3) &&
        (change_interval_time > LED_BLINK_TIME - 10))
    {
        led_on(led_res_p->pin, (LED_E_EXCEPTION == led_res_p->current_state) ? 0 : 1);
        led_res_p->current_state = (LED_E_EXCEPTION == led_res_p->current_state) ? LED_E_NORMAL : LED_E_EXCEPTION;
        led_res_p->change_time = current_tick;
        // TRACE_D("led change and change time %d", current_tick);
    }

    // 判断当前时间是否在闪烁时间范围外，如果是，则恢复引脚电平，并重置相关变量
    if ((start_interval_time > LED_BLINK_TIME * 3) && (led_res_p->event_start_time))
    {
        // TRACE_D("led to recover %d, start_interval_time %d", led_res_p->recover, start_interval_time);
        led_on(led_res_p->pin, (LED_E_EXCEPTION == led_res_p->recover) ? 1 : 0);
        led_res_p->current = LED_E_DEF;
        led_res_p->current_state = LED_E_DEF;
        led_res_p->event_start_time = 0;
        led_res_p->change_time = 0;
    }
}

static int set_led_event(led_res_t *led_res_p, const led_msg_data_t *data)
{
    int ret = 1;
    if ((RT_NULL == led_res_p) || (RT_NULL == data) || (data->id >= LED_RESOURCE_SIZE))
    {
        return ret;
    }
    led_res_t *ptr = &led_res_p[data->id];

    if (RT_NULL == ptr)
        return ret;

    // TRACE_D("pin %d id %d e %d", ptr->pin, data->id, data->e);

    switch (data->e)
    {
    case LED_E_EXCEPTION:
    case LED_E_NORMAL:
        led_on(ptr->pin, (LED_E_EXCEPTION == data->e) ? 1 : 0);
        ptr->recover = data->e;
        ret = 0;
        break;
    case LED_E_BLINK:
        ptr->current = data->e;
        if (LED_E_DEF == ptr->current_state)
        {
            ptr->current_state = LED_E_NORMAL;
            ptr->event_start_time = rt_tick_get();
            ptr->change_time = ptr->event_start_time;
        }
        ret = 0;
        break;
    default:
        break;
    } // !switch (data->e)
    return ret;
}

////////////////////////////////////////////////////////////////////////////////

// int led_manager_create_queue(void)
// {
//     // create wiota app manager queue.
//     led_queue_handle = manager_create_queue("led_mq", 4, 5, UC_SYSTEM_IPC_FLAG_PRIO);
//     if (led_queue_handle == RT_NULL)
//     {
//         TRACE_E("manager_create_queue error");
//         return 1;
//     }
//     return 0;
// }

// void *get_led_manager_queue(void)
//{
//     return led_queue_handle;
// }

void led_manager_task(void *pPara)
{
    int ret = 0;
    module_queue_message_t *page = RT_NULL;
    // TRACE_D("led_manager_task begin");

    led_pin_init();

    while (1)
    {
#if 0
        // 从队列中接收消息
        ret = manager_recv_queue(led_queue_handle, (void *)&page, LED_QUEUE_TIMEOUT);
        if ((QUEUE_EOK == ret) && (RT_NULL != page) && (LED_MANAGER_CMD == page->cmd))
        {
            // TRACE_D("led_manager_task recv message");
            set_led_event(s_led_resource, page->data);
        }
        // 释放消息内存
        if (RT_NULL != page)
        {
            if (RT_NULL != page->data)
            {
                rt_free(page->data);
                page->data = RT_NULL;
            }
            rt_free(page);
            page = RT_NULL;
        }
#endif
        // 延时1s
        rt_thread_mdelay(200);

        // 遍历LED资源
        for (int num = 0; num < LED_RESOURCE_SIZE; num++)
        {
            // 处理LED资源
            if (LED_E_BLINK == s_led_resource[num].current)
            {
                led_blink_once(&s_led_resource[num]);
            }
            else if (LED_E_BLINK_KEEP == s_led_resource[num].recover)
            {
                led_blink_keep(&s_led_resource[num]);
            }
        }
    } // !while (1)
}

int send_led_event(led_id_e id, led_event_e e)
{
    int ret = 0;
    led_msg_data_t msg_data = {0};

    switch (e)
    {
    case LED_E_DEF:
    case LED_E_BLINK_KEEP:
        ret = 1;
        break;
    case LED_E_EXCEPTION:
    case LED_E_NORMAL:
    case LED_E_BLINK:
        ret = 0;
        break;
    default:
        ret = 1;
        break;
    }

    if (ret)
    {
        return ret;
    }

#if 0
    led_msg_data_t *msg_data = rt_malloc(sizeof(led_msg_data_t));
    if (RT_NULL == msg_data)
    {
        TRACE_E("led msg malloc error");
        return 2;
    }
    msg_data->id = id;
    msg_data->e = e;
    if (module_queue_communication(get_led_manager_queue(),
                                   GATEWAY_MODULE_DEFAULT,
                                   LED_MANAGER_MODULE,
                                   LED_MANAGER_CMD,
                                   (void *)msg_data))
    {
        TRACE_E("led send message error");
        rt_free(msg_data);
        return 3;
    }
#endif

    msg_data.id = id;
    msg_data.e = e;

    return set_led_event(s_led_resource, &msg_data);
}
